package com.googlecode.gwtCorsForIe8.server;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class GWTRequest implements HttpServletRequest {

	public static class HeadersAndData {

		private final Map<String, String> headers;
		private final String data;

		public Map<String, String> getHeaders() {
			return headers;
		}

		public String getData() {
			return data;
		}

		public HeadersAndData(Map<String, String> headers, String data) {
			this.headers = headers;
			this.data = data;
		}

	}

	private static HeadersAndData decodeHeaders(String data) {
		System.out.println(data);
		int indexOf = data.indexOf(';');
		System.out.println(indexOf);
		if (indexOf < 0) {
			return new HeadersAndData(null, data);
		}
		String num = data.substring(0, indexOf);
		System.out.println(num);
		String prefix;
		try {
			int zeichen = Integer.parseInt(num);
			prefix = data.substring(indexOf + 1, indexOf + 1 + zeichen);
			System.out.println(prefix);
			data = data.substring(indexOf + 1 + zeichen);
		} catch (NumberFormatException nf) {
			return new HeadersAndData(null, data);
		}
		System.out.println(data);
		List<String> headerEncoded = new LinkedList<String>();
		Map<String, String> headers = new HashMap<String, String>();
		int pos = 0;
		while (pos < prefix.length()) {
			int newPos = pos;
			while (newPos == pos
					|| (newPos >= 0 && (newPos == 0 || prefix
							.charAt(newPos - 1) == '\\'))) {
				newPos = prefix.indexOf(';', newPos + 1);
			}
			String substring = prefix.substring(pos, newPos);
			System.out.println(substring);
			headerEncoded.add(substring);
			pos = newPos + 1;
		}
		Iterator<String> iterator = headerEncoded.iterator();
		while (iterator.hasNext()) {
			String key = iterator.next();
			if (!iterator.hasNext()) {
				throw new RuntimeException();
			}
			String value = iterator.next();
			key = key.replace("\\;", ";");
			value = value.replace("\\;", ";");
			headers.put(key, value);
		}
		System.out.println(headers);
		return new HeadersAndData(headers, data);
	}

	private HttpServletRequest request;
	private Map<String, String> headers;
	private ByteArrayInputStream inputStream;
	private int contentLength;
	private String contextPath;

	public GWTRequest(HttpServletRequest request, String contextPath) {
		this.contextPath = contextPath;
		this.request = request;
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		byte[] buf = new byte[4096];
		try {
			ServletInputStream in = request.getInputStream();
			int read = in.read(buf);
			while (read >= 0) {
				bout.write(buf, 0, read);
				read = in.read(buf);
			}
			bout.close();
			HeadersAndData decodeHeaders = decodeHeaders(new String(bout
					.toByteArray()));
			this.headers = decodeHeaders.getHeaders();
			byte[] bytes = decodeHeaders.getData().getBytes();
			this.inputStream = new ByteArrayInputStream(bytes);
			this.contentLength = bytes.length;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public Object getAttribute(String arg0) {
		return request.getAttribute(arg0);
	}

	public Enumeration getAttributeNames() {
		return request.getAttributeNames();
	}

	public String getAuthType() {
		return request.getAuthType();
	}

	public String getCharacterEncoding() {
		String header = this.getHeader("Content-Type");
		int indexOf = header.indexOf("charset=");
		if (indexOf < 0) {
			return null;
		}
		return header.substring(indexOf + 8);

	}

	public int getContentLength() {
		return this.contentLength;
	}

	public String getContentType() {
		return this.getHeader("Content-Type");
	}

	public String getContextPath() {
		return contextPath != null ? contextPath : request.getContextPath();
	}

	public Cookie[] getCookies() {
		return request.getCookies();
	}

	public long getDateHeader(String arg0) {
		return request.getDateHeader(arg0);
	}

	public String getHeader(String header) {
		String value = request.getHeader(header);
		if (value == null) {
			value = this.headers.get(header);
		}
		System.out.println("GetHeader " + header + ": " + value);
		if ("X-GWT-Permutation".equals(header)) {
			// return null;
		}
		return value;

	}

	public Enumeration getHeaderNames() {
		return request.getHeaderNames();
	}

	public Enumeration getHeaders(String arg0) {
		return request.getHeaders(arg0);
	}

	public ServletInputStream getInputStream() throws IOException {
		return new MyServletInputStream(inputStream);
	}

	public int getIntHeader(String arg0) {
		return request.getIntHeader(arg0);
	}

	public String getLocalAddr() {
		return request.getLocalAddr();
	}

	public String getLocalName() {
		return request.getLocalName();
	}

	public int getLocalPort() {
		return request.getLocalPort();
	}

	public Locale getLocale() {
		return request.getLocale();
	}

	public Enumeration getLocales() {
		return request.getLocales();
	}

	public String getMethod() {
		return request.getMethod();
	}

	public String getParameter(String arg0) {
		return request.getParameter(arg0);
	}

	public Map getParameterMap() {
		return request.getParameterMap();
	}

	public Enumeration getParameterNames() {
		return request.getParameterNames();
	}

	public String[] getParameterValues(String arg0) {
		return request.getParameterValues(arg0);
	}

	public String getPathInfo() {
		return request.getPathInfo();
	}

	public String getPathTranslated() {
		return request.getPathTranslated();
	}

	public String getProtocol() {
		return request.getProtocol();
	}

	public String getQueryString() {
		return request.getQueryString();
	}

	public BufferedReader getReader() throws IOException {
		return request.getReader();
	}

	public String getRealPath(String arg0) {
		return request.getRealPath(arg0);
	}

	public String getRemoteAddr() {
		return request.getRemoteAddr();
	}

	public String getRemoteHost() {
		return request.getRemoteHost();
	}

	public int getRemotePort() {
		return request.getRemotePort();
	}

	public String getRemoteUser() {
		return request.getRemoteUser();
	}

	public RequestDispatcher getRequestDispatcher(String arg0) {
		return request.getRequestDispatcher(arg0);
	}

	public String getRequestURI() {
		return request.getRequestURI();
	}

	public StringBuffer getRequestURL() {
		return request.getRequestURL();
	}

	public String getRequestedSessionId() {
		return request.getRequestedSessionId();
	}

	public String getScheme() {
		return request.getScheme();
	}

	public String getServerName() {
		return request.getServerName();
	}

	public int getServerPort() {
		return request.getServerPort();
	}

	public String getServletPath() {
		return request.getServletPath();
	}

	public HttpSession getSession() {
		return request.getSession();
	}

	public HttpSession getSession(boolean arg0) {
		return request.getSession(arg0);
	}

	public Principal getUserPrincipal() {
		return request.getUserPrincipal();
	}

	public boolean isRequestedSessionIdFromCookie() {
		return request.isRequestedSessionIdFromCookie();
	}

	public boolean isRequestedSessionIdFromURL() {
		return request.isRequestedSessionIdFromURL();
	}

	public boolean isRequestedSessionIdFromUrl() {
		return request.isRequestedSessionIdFromUrl();
	}

	public boolean isRequestedSessionIdValid() {
		return request.isRequestedSessionIdValid();
	}

	public boolean isSecure() {
		return request.isSecure();
	}

	public boolean isUserInRole(String arg0) {
		return request.isUserInRole(arg0);
	}

	public void removeAttribute(String arg0) {
		request.removeAttribute(arg0);
	}

	public void setAttribute(String arg0, Object arg1) {
		request.setAttribute(arg0, arg1);
	}

	public void setCharacterEncoding(String arg0)
			throws UnsupportedEncodingException {
		request.setCharacterEncoding(arg0);
	}

}
